/**
 * reference: https://github.com/clbond/form-example
 */
import { Directive } from '@angular/core';
import {NgModel} from '@angular/forms';

import {Observable} from 'rxjs';
import {map} from 'rxjs/operators';


import {ValueAccessorBase} from './value-accessor';

import {
  AsyncValidatorArray,
  ValidatorArray,
  ValidationResult,
  validate,
} from './validate';

export class ValidationObject {
  key: string;
  value: string | boolean;
}

@Directive()
export abstract class ElementBase<T> extends ValueAccessorBase<T> {
  protected abstract model: NgModel;

  constructor(
    private validators: ValidatorArray,
    private asyncValidators: AsyncValidatorArray,
  ) {
    super();
  }

  protected validate(): Observable<ValidationResult> {
    return validate
      (this.validators, this.asyncValidators)
      (this.model.control);
  }

  get invalid(): Observable<boolean> {
    return this.validate().pipe(map(v => Object.keys(v || {}).length > 0));
  }

  get failures(): Observable<ValidationObject[]> {
    return this.validate().pipe(
      map(v => Object.keys(v).map((key) => ({ key, value: v[key] }))),
    );
  }

  get initialized() {
    return [null, undefined, ''].indexOf(this.initialValue as any) === -1;
  }

  /**
   * 能否启动当前表单项验证
   */
  get shouldValidate() {
    return !this.disabled && (this.model.touched || this.initialized);
  }

  /**
   * 用于间接更改model值的组件，如checkbox-group
   */
  markAsDirty() {
    this.model.control.markAsTouched();
    this.model.control.markAsDirty();
  }
}
